import { BaseData } from "../../datavo/DataCustom";
import Utils from "../utils/Utils";
import { transformValues } from "./DataCommon";

export class DataItem<T extends BaseData> {

    //字段key列表
    private _keyList: string[] = [];

    //源数据表
    private _dataArray = new Map<number, T>();

    //数据缓存
    private _dataCache = new Map<string, T>();


    private _length = 0;

    private _min: T;

    private _max: T;

    public readonly dataName: string;

    /**
     * 初始化表
     * @param class_c 表类型  
     * @param data 表数据
     */
    constructor(class_c: new () => T, data: any) {
        data = data || [];
        this._keyList = data.shift();
        this._length = data.length;
        this.dataName = class_c["dataName"];

        for (let i = 0; i < data.length; i++) {

            let dataC = new class_c();
            for (let j = 0; j < data[i].length; j++) {
                let key: keyof T = this._keyList[j];
                let value = data[i][j];
                value = transformValues(this.dataName, key, value);
                if (j === 0) {
                    value = Utils.parseNum(value);
                    Reflect.defineProperty(dataC, "ID", { value: value, writable: false, configurable: false });
                }
                Reflect.defineProperty(dataC, key, { value: value, writable: false, configurable: false });
            }
            this._dataArray.set(dataC.ID, dataC);
        }
    }

    *[Symbol.iterator]() {
        yield* this._dataArray.values();
    }


    foreach(callback: (value: T, key: number) => void) {
        this._dataArray.forEach((v, k) => callback(v, k));
    }

    findOneByID(id: number): T {
        return this._dataArray.get(id);
    }

    findOne(key: keyof T, value: any): T {
        return this.findOneByItem({ [key]: value } as any);
    }

    findOneByItem(item: Partial<T>, cache: boolean = false): T {
        let kvs = [];
        for (let key in item) {
            kvs.push(key, item[key]);
        }

        if (cache) {
            let key = kvs.join();
            let v = this._dataCache.get(key);
            if (!v) {
                v = this.find(...kvs)[0];
                this._dataCache.set(key, v);
            }

            return v;
        }

        return this.find(...kvs)[0];
    }


    findByItem(item: Partial<T>): T[] {
        let kvs = [];
        for (let key in item) {
            kvs.push(key, item[key]);
        }
        return this.find(...kvs);
    }

    /**
     * 根据kvs查找满足条件的列表
     * @param kvs [key1,value1,key2,value2]
     * @returns 
     */
    find(...kvs: any): T[] {
        if (!kvs || (kvs.length & 1) != 0) {
            return;
        }

        let results = [];
        for (let elm of this._dataArray.values()) {

            let isFind = true;
            for (let i = 0; i < kvs.length; i += 2) {
                let key: keyof T = kvs[i];
                let value = kvs[i + 1];

                if (elm[key] != value) {
                    isFind = false;
                    break;
                }
            }

            if (isFind) {
                results.push(elm);
            }
        }

        return results;
    }


    /**ID最小的数据 */
    get minIdData(): T {
        if (this._min) {
            return this._min;
        }

        let min = -1;
        for (let elm of this._dataArray.values()) {
            if (min === -1 || elm.ID < min) {
                min = elm.ID;
            }
        }

        this._min = this._dataArray.get(min);
        return this._min;
    }


    /**ID最大的数据 */
    get maxIdData(): T {
        if (this._max) {
            return this._max;
        }

        let max = -1;
        for (let elm of this._dataArray.values()) {
            if (max === -1 || elm.ID > max) {
                max = elm.ID;
            }
        }

        this._max = this._dataArray.get(max);
        return this._max;

    }

    get length(): number {
        return this._length;
    }

    get name(): string {
        return this.dataName;
    }

    get toArray(): T[] {
        return Array.from(this._dataArray.values());
    }

}